#pragma once
#include <array>
#include <memory>
#include <string>
#include <iostream>
#include "asio.hpp"
#include <sigc++/sigc++.h>

class AsyncSession : public std::enable_shared_from_this<AsyncSession> {
public:
    AsyncSession(asio::ip::tcp::socket socket)
        : socket_(std::move(socket)) {}

    sigc::signal<void(std::shared_ptr<AsyncSession>, const std::string&)> signal_message_received;
    sigc::signal<void(std::shared_ptr<AsyncSession>)> signal_disconnected;

    void start() { do_read(); }

    void send(const std::string& msg) {
        auto self = shared_from_this();
        asio::async_write(socket_, asio::buffer(msg),
            [self](std::error_code ec, std::size_t) {
                if (ec) self->signal_disconnected(self);
            });
    }

private:
    void do_read() {
        auto self = shared_from_this();
        socket_.async_read_some(asio::buffer(buffer_),
            [self](std::error_code ec, std::size_t len) {
                if (!ec) {
                    self->signal_message_received(self, std::string(self->buffer_.data(), len));
                    self->do_read();
                } else {
                    self->signal_disconnected(self);
                }
            });
    }

    asio::ip::tcp::socket socket_;
    std::array<char, 1024> buffer_;
};

